#ifndef TYPES_HPP
#define TYPES_HPP
#include <string>

using namespace std;

// Representa operadores lógicos, aritméticos, de atribuição e de negação.
enum Operator {
    OP_SUM, OP_SUB, OP_MUL, OP_DIV, OP_MOD,
    OP_ASG,
    OP_EQL, OP_DIF,
    OP_LES, OP_GRT, OP_LEQ, OP_GEQ,
    OP_AND, OP_OR, OP_NEG,
    OP_DRF,
    OP_IN, OP_POW
};

// Funções de conversão
string itos(int);
int stoi(string);

// Representação de um tipo. Esta classe visa facilitar as validações de tipo
// em expressões aritméticas e atribuições de valores, além de fornecer métodos
// Para traduzir a declaração de uma variável de um certo tipo para o
// correspondente em C-Assembly.
class Type {
private:
    string _name;
    Type* _undertype;
    int _dimension;
    string _dimstr;
protected:
    Type(string name, Type* undertype, int dimension);
    Type(string name, Type* undertype, string dimension);
public:
    // Nome do tipo em nossa linguagem.
    string name();
    // Sufixo para variáveis temporárias.
    virtual string tempsuffix() = 0;
    // Tradução do tipo para um tipo em C-Assembly.
    virtual string cname() = 0;
    // String com a declaração em C-Assembly 
    // de uma variável 'var' deste tipo.
    virtual string cdec(string var) = 0;
    // Dimensão do tipo (em string).
    string cderef(string var, int index);
    string cderef(string var, string index);
    string dec(string var);
    string dimstr();
    // Espaço ocupado em memória por uma variável
    // deste tipo.
    virtual int size() = 0;
    // Dimensão do tipo. Vale 1 para tipos simples.
    int dimension();
    // Tipo subjacente. NULL para tipos simples, mas
    // não para tipos complexos como vector(int:3),
    // por exemplo.
    Type* undertype();
    // True se o tipo for simples, o que ocorre se o
    // tipo subjacente for nulo.
    bool simple();
    bool complex();
    virtual bool numeric() = 0;
    virtual bool real() = 0;
    virtual bool integer() = 0;
    virtual bool natural() = 0;
    virtual bool character() = 0;
    virtual bool logic() = 0;
    bool equals(Type*);
    bool equals(Type&);
    virtual bool receives(Type&);
    virtual bool receives(Type*);
    // Operadores atitméticos. Por padrão, nenhuma operação está definida.
    virtual Type * operator +(Type& t);
    virtual Type * operator -(Type& t);
    virtual Type * operator -();
    virtual Type * operator *(Type& t);
    virtual Type * operator /(Type& t);
    virtual Type * operator %(Type& t);
    // Operadores de relação de ordem. Por padrão, nenhum está definido.
    virtual Type * operator>(Type& t);
    virtual Type * operator<(Type& t);
    virtual Type * operator >=(Type& t);
    virtual Type * operator <=(Type& t);
    // Operadores lógicos. Por padrão, nenhum está definido.
    virtual Type * operator !();
    virtual Type * operator &&(Type& t);
    virtual Type * operator ||(Type& t);
    // Operador de derreferenciação. Sempre retorna undertype().
    virtual Type * operator *();
    virtual string operator[](int index);
    virtual string operator[](string index);
};

class SimpleType : public Type {
private:
    string _cname;
    int _size;
protected:
    SimpleType(string name, string cname, int size);
public:
    virtual string tempsuffix();
    virtual string cname();
    virtual string cdec(string var);
    virtual int size();
};

class NumericType : public SimpleType {
protected:
    NumericType(string name, string cname, int size);
public:
    static Type* stronger(Type*, Type*);
    static Type* stronger(Type*, Type&);
    static Type* stronger(Type&, Type*);
    static Type* stronger(Type&, Type&);
    virtual bool numeric();
    virtual bool real() = 0;
    virtual bool integer() = 0;
    virtual bool natural() = 0;
    virtual bool character() = 0;
    virtual bool logic();
    virtual bool receives(Type&);
    virtual bool receives(Type*);
    virtual Type * operator +(Type& t);
    virtual Type * operator -(Type& t);
    virtual Type * operator -();
    virtual Type * operator *(Type& t);
    virtual Type * operator /(Type& t);
    virtual Type * operator %(Type& t);
    virtual Type * operator>(Type& t);
    virtual Type * operator<(Type& t);
    virtual Type * operator >=(Type& t);
    virtual Type * operator <=(Type& t);
};

class Real : public NumericType {
private:
    static Type *_type;
    Real();
protected:
    Real(string name, string cname, int size);
public:
    static Type* type();
    virtual bool real();
    virtual bool character();
    virtual bool integer();
    virtual bool natural();
};

class Int : public Real {
private:
    static Type *_type;
    Int();
protected:
    Int(string name, string cname, int size);
public:
    static Type* type();
    virtual bool integer();
    virtual bool natural();
    virtual bool receives(Type&);
    virtual bool receives(Type*);
};

class Nat : public Int {
private:
    static Type *_type;
    Nat();
public:
    static Type* type();
    virtual bool natural();
    virtual Type * operator -(Type& t);
    virtual Type * operator -();
};

class Char : public Int {
private:
    static Type *_type;
    Char();
public:
    static Type* type();
    virtual bool character();
    virtual Type * operator +(Type& t);
    virtual bool receives(Type&);
    virtual bool receives(Type*);
};

class Logic : public SimpleType {
private:
    static Type *_type;
    Logic();
public:
    static Type* type();
    virtual bool numeric();
    virtual bool real();
    virtual bool integer();
    virtual bool natural();
    virtual bool character();
    virtual bool logic();
    virtual string tempsuffix();
    virtual Type * operator !();
    virtual Type * operator &&(Type& t);
    virtual Type * operator ||(Type& t);
};

class ComplexType : public Type {
protected:
    ComplexType(string name, Type* undertype, int dimension);
    ComplexType(string name, Type* undertype, string dimension);
public:
    virtual string tempsuffix();
    virtual string cname();
    virtual string cdec(string var);
    virtual int size();
    virtual bool numeric();
    virtual bool real();
    virtual bool integer();
    virtual bool natural();
    virtual bool character();
    virtual bool logic();
    virtual bool receives(Type&);
    virtual bool receives(Type*);
};

class Array : public ComplexType {
public:
    Array(Type *undertype, int dimension);
    Array(Type *undertype, string dimension);
};

class Vector : public ComplexType {
public:
    Vector(Type *undertype, int dimension);
    Vector(Type *undertype, string dimension);
    virtual Type * operator +(Type& t);
    virtual Type * operator -(Type& t);
    virtual Type * operator *(Type& t);
};

class String : public ComplexType {
public:
    String(string dimension);
    String(int dimension);
    virtual Type * operator +(Type& t);
};

class Set : public ComplexType {
public:
    Set(Type *undertype);
};

#endif /* TYPES_HPP */
